/* 该程序用来计算随机选取值的正弦平均值，来估算0~1这个区间内sin(x)的平均值
 * main程序中的循环在0~1之间选择一个随机值x，将sin(x)的值添加到一个不断变化的总和中，将计数值加1，并打印当前的计数值和平均值
 * 程序说明了如何用信号处理函数优雅地终止一个程序。
 * 用户在标准输入中输入Ctrl-C时，信号处理函数就会设置doneflag来说明程序应该终止。
 * 在计算循环的每次迭代中，程序都会检测doneflag，判断是否应该退出循环并打印最后一条消息。
 * */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

// note : 使用math.h中的sin函数时，如果进行编译需要使用 -lm 命令，既gcc test5.c -lm -o test5
// gcc sin.c -lm -o sin等价于gcc sin.c -lm -L/lib -L/usr/lib -o sin

// typedef int sig_atomic_t; // 在signal.h中的定义
// sig_atomic_t是一个小到足以进行原子访问的整数类型
// volatile通知编译器该变量的修改可能与程序的执行时异步的，否则，编译器可能会假设doneflag在while循环中没有被修改，
// 进而生成只在循环的第一次迭代中对条件进行检测的代码。
static volatile sig_atomic_t doneflag = 0;

// note : 只有当信号处理函数和main函数同时使用printf和perror时，信号安全才会成为问题
// 而在该程序中，只有main函数使用了printf和perror，因此不会产生信号安全问题。

// ARGSUSED
static void setdoneflag(int signo) {
    doneflag = 1;
}

int main(void) {
    // 设置信号处理函数变量
    struct sigaction act;
    int count = 0;
    double sum = 0.0;
    double x;

    act.sa_flags = 0;
    act.sa_handler = setdoneflag;

    // SIGINT为交互式信号（Ctrl-C）
    if (sigemptyset(&act.sa_mask) == -1 || sigaction(SIGINT, &act, NULL) == -1) {
        perror("Faile to set SIGINT handler");
        return -1;
    }
    // doneflag = 1;
    while (!doneflag) {
        x = (rand() + 0.5) / (RAND_MAX + 1.0);
        sum += sin(x);
        count++;
        printf("Count is %d and average is %f\n", count, sum/count);
        sleep(1);
    }

    printf("Program terminating ...\n");
    if (count == 0) 
        printf("No values calculated yet\n");
    else 
        printf("Count is %d and average is %f\n", count, sum/count);

    return 0;
}